import { _decorator, Component, Sprite, UITransform } from 'cc';
import { CTRL_ENUM, DIRECTION_ENUM, DIRECTION_ORDER_ENUM, ENTITY_STATE_ENUM, ENTITY_TYPE_ENUM, EVENT_ENUM, PARAMS_NAME_ENUM, PLAYER_DEAD_TYPE } from '../../Enum';
import { TILE_WEIGHT, TILE_HEIGHT } from '../Tile/TileItem';
import { EventManager } from '../../RunTime/EventManager';
import { PlayerStateMachine } from './PlayerStateMachine';
import { EntiyManager } from '../../common/EnityManager';
import { DataManager } from '../../RunTime/DataManager';
import { WoodenSkeletonManager } from '../WoodenSkeleton/WoodenSkeletonManager';
import { IEntity } from '../../Levels';
import { EnemyManager } from '../../common/EnemyManager';
import { DoorManager } from '../Door/DoorManager';
const { ccclass, property } = _decorator;


@ccclass('PlayerManager')
export class PlayerManager extends EntiyManager {

  // 移动使用
  targetX: number = 0
  targetY: number = 0
  readonly speed: number = 0.1
  in_moving: boolean = false


  async init(param: IEntity){
    this.fsm = this.addComponent(PlayerStateMachine)
    await this.fsm.init()
    super.init(param)
    this.node.setPosition(this.x * TILE_WEIGHT - 1.5*TILE_WEIGHT, -this.y * TILE_HEIGHT + 1.5*TILE_HEIGHT)
    this.targetX = this.x
    this.targetY = this.y
    const dataManagerInstance =  DataManager.getInstance()
    dataManagerInstance.player = this
    EventManager.getInstance().on(EVENT_ENUM.PLAYER_CTRL, this.InputCtrl, this)
    EventManager.getInstance().emit(EVENT_ENUM.PLAYER_BORN)
    EventManager.getInstance().on(EVENT_ENUM.PLAYER_DIE, this.OnDead, this)
  }

  onDestroy(): void {
    EventManager.getInstance().off(EVENT_ENUM.PLAYER_DIE, this.OnDead)
    EventManager.getInstance().off(EVENT_ENUM.PLAYER_CTRL, this.InputCtrl)
  }


  update(){
    this.updateXY()
    this.node.setPosition(this.x * TILE_WEIGHT - 1.5*TILE_WEIGHT, -this.y * TILE_HEIGHT + 1.5*TILE_HEIGHT)
    // if (this.updateXY()) {
    //   this.node.setPosition(this.x * TILE_WEIGHT - 1.5*TILE_WEIGHT, -this.y * TILE_HEIGHT + 1.5*TILE_HEIGHT)
    // }
  }

  updateXY(): boolean {
    if (this.x > this.targetX) {
      this.x -= this.speed
    } else if (this.x < this.targetX) {
      this.x += this.speed
    }

    if (this.y > this.targetY) {
      this.y -= this.speed
    } else if (this.y < this.targetY) {
      this.y += this.speed
    }

    if(Math.abs(this.x - this.targetX) < 0.01 && Math.abs(this.y - this.targetY) < 0.01 && this.in_moving ){
      this.x = this.targetX
      this.y = this.targetY
      this.in_moving = false
      EventManager.getInstance().emit(EVENT_ENUM.PLAYER_MOVE_END)
    }
    return this.x !== this.targetX || this.y !== this.targetY ? true : false
  }

  InputCtrl(CTRL: CTRL_ENUM){
    if(this.in_moving || this.state == ENTITY_STATE_ENUM.DEAD || this.state == ENTITY_STATE_ENUM.AIRDEAD || this.state == ENTITY_STATE_ENUM.ATTACK) {
      return
    }
    this.checkAndMoveAttack(CTRL)
    this.checkAndTurn(CTRL)
  }

  getWeaponXY(currentDirection: DIRECTION_ENUM){
    let weaponX = this.targetX
    let weaponY = this.targetY
    if(currentDirection == DIRECTION_ENUM.TOP) weaponY -=1
    else if(currentDirection == DIRECTION_ENUM.BOTTOM) weaponY +=1
    else if(currentDirection == DIRECTION_ENUM.LEFT) weaponX -=1
    else if(currentDirection == DIRECTION_ENUM.RIGHT) weaponX +=1
    return {x:weaponX, y:weaponY}
  }

  checkAndMoveAttack(CTRL: CTRL_ENUM){
    const {enemys, door, bursts} = DataManager.getInstance()

    const WeaponXY = this.getWeaponXY(this.direction)

    const {x: doorX, y: doorY, state: doorState} = door

    let preX = this.targetX
    let preY = this.targetY
    let preWeaponX = WeaponXY.x
    let preWeaponY = WeaponXY.y
    let canMove = true

    let cantMoveState: ENTITY_STATE_ENUM = this.state
    let attackObj = (x: number, y: number) => {
      const index = enemys.findIndex(e => e.state !== ENTITY_STATE_ENUM.DEAD && e.x == x && e.y == y)
      if (index >= 0) {
        return enemys[index]
      } else {
        return null
      }
    }

    let burstInLoc = (x: number, y: number) => {
      return bursts.some(burst => burst.isInState(ENTITY_STATE_ENUM.DEAD) == false && burst.x === x && burst.y === y)
    }

    if(CTRL === CTRL_ENUM.TOP) {
      preY -= 1
      preWeaponY -= 1
      cantMoveState = ENTITY_STATE_ENUM.BLOCKFRONT
    }
    else if (CTRL === CTRL_ENUM.BOTTOM){
      preY += 1
      preWeaponY += 1
      cantMoveState = ENTITY_STATE_ENUM.BLOCKBACK
    }
    else if (CTRL === CTRL_ENUM.LEFT) {
      preX -= 1
      preWeaponX -= 1
      cantMoveState = ENTITY_STATE_ENUM.BLOCKLEFT
    }
    else if (CTRL === CTRL_ENUM.RIGHT) {
      preX += 1
      preWeaponX += 1
      cantMoveState = ENTITY_STATE_ENUM.BLOCKRIGHT
    }
    else canMove = false

    const obj = attackObj(preWeaponX, preWeaponY)
    // 可以移动，并且武器前面是可攻击对象
    if (canMove && obj) {
      EventManager.getInstance().emit(EVENT_ENUM.RECORD_STEP)
      this.state = ENTITY_STATE_ENUM.ATTACK
      EventManager.getInstance().emit(EVENT_ENUM.PLAYER_ATTACK, obj.id)
    }else if ( (canMove && burstInLoc(preX, preY)) || (canMove && burstInLoc(preWeaponX, preWeaponY)) ){
      EventManager.getInstance().emit(EVENT_ENUM.RECORD_STEP)
      this.targetX = preX
      this.targetY = preY
      this.in_moving = true
    }else if (canMove) {
      // 门开了
      if 
      (
        (doorState == ENTITY_STATE_ENUM.DEAD && ((preX == doorX && preY == doorY) || (preWeaponX == doorX && preWeaponY == doorY))) 
        ||
        this.tilesMovable(preX,preY) && this.tilesMovable(preWeaponX,preWeaponY) &&
        (preX == doorX && preY == doorY) == false &&
        (preWeaponX == doorX && preWeaponY == doorY) == false
      ){
        EventManager.getInstance().emit(EVENT_ENUM.RECORD_STEP)
        EventManager.getInstance().emit(EVENT_ENUM.SHOW_SMOKE, this.targetX, this.targetY, this.direction)
        this.targetX = preX
        this.targetY = preY
        this.in_moving = true
      }else {
        this.state = cantMoveState
        EventManager.getInstance().emit(EVENT_ENUM.SHAKE, this.direction)
      }
    }else {

    }


  }

  tilesMovable(x: number, y: number) {
    const {tiles} = DataManager.getInstance()
    if (tiles.length > x+1 && tiles[x].length > y+1){
      return tiles[x][y]?.movable
    }
    return false
  }
  tilesTurnble(x: number, y: number) {
    const {tiles} = DataManager.getInstance()
    if (tiles.length > x+1 && tiles[x].length > y+1){
      return tiles[x][y]?.turnable
    }
    return false
  }

  checkAndTurn(CTRL: CTRL_ENUM) {
    const {enemys} = DataManager.getInstance()
    let preDirection: DIRECTION_ENUM
    let diagonalX = this.targetX
    let diagonalY = this.targetY
    let succ_state: ENTITY_STATE_ENUM
    let fail_state: ENTITY_STATE_ENUM

    let enemyInLoc = (x: number, y: number) => {
      return enemys.some(enemy => enemy.isInState(ENTITY_STATE_ENUM.DEAD) == false && enemy.x === x && enemy.y === y)
    }

    if (CTRL == CTRL_ENUM.TURNLEFT){
      succ_state = ENTITY_STATE_ENUM.TURNLEFT
      fail_state = ENTITY_STATE_ENUM.BLOCKTURNLEFT
      if(this.direction === DIRECTION_ENUM.TOP) {
        preDirection = DIRECTION_ENUM.LEFT
        diagonalX = this.targetX - 1
        diagonalY = this.targetY - 1
      }
      else if(this.direction === DIRECTION_ENUM.LEFT) {
        preDirection = DIRECTION_ENUM.BOTTOM
        diagonalX = this.targetX - 1
        diagonalY = this.targetY + 1
      }
      else if(this.direction === DIRECTION_ENUM.BOTTOM) {
        preDirection = DIRECTION_ENUM.RIGHT
        diagonalX = this.targetX + 1
        diagonalY = this.targetY + 1
      }
      else if(this.direction === DIRECTION_ENUM.RIGHT) {
        preDirection = DIRECTION_ENUM.TOP
        diagonalX = this.targetX + 1
        diagonalY = this.targetY - 1
      }
    } else if (CTRL == CTRL_ENUM.TURNRIGHT){
      succ_state = ENTITY_STATE_ENUM.TURNRIGHT
      fail_state = ENTITY_STATE_ENUM.BLOCKTURNRIGHT
      if(this.direction === DIRECTION_ENUM.TOP) {
        preDirection = DIRECTION_ENUM.RIGHT
        diagonalX = this.targetX + 1
        diagonalY = this.targetY - 1
      }
      else if(this.direction === DIRECTION_ENUM.RIGHT) {
        preDirection = DIRECTION_ENUM.BOTTOM
        diagonalX = this.targetX + 1
        diagonalY = this.targetY + 1
      }
      else if(this.direction === DIRECTION_ENUM.BOTTOM) {
        preDirection = DIRECTION_ENUM.LEFT
        diagonalX = this.targetX - 1
        diagonalY = this.targetY + 1
      }
      else if(this.direction === DIRECTION_ENUM.LEFT) {
        preDirection = DIRECTION_ENUM.TOP
        diagonalX = this.targetX - 1
        diagonalY = this.targetY - 1
      }

    }

    if (succ_state && fail_state){

      const WeaponXY = this.getWeaponXY(this.direction)
      const preWeaponXY = this.getWeaponXY(preDirection)
      if (
        this.tilesTurnble(preWeaponXY.x, preWeaponXY.y) && this.tilesTurnble(WeaponXY.x, WeaponXY.y) && this.tilesTurnble(diagonalX, diagonalY) &&
        !enemyInLoc(diagonalX, diagonalY) && !enemyInLoc(WeaponXY.x, WeaponXY.y) && !enemyInLoc(preWeaponXY.x, preWeaponXY.y)
      ) {
        this.direction = preDirection
        this.state = succ_state
        EventManager.getInstance().emit(EVENT_ENUM.PLAYER_TURN)
      } else {
        // 震动
        this.state = fail_state
      }

    }

  }

  OnDead(type: PLAYER_DEAD_TYPE) {

    if (type == PLAYER_DEAD_TYPE.ENEMY_ATTACK) {
      this.state = ENTITY_STATE_ENUM.DEAD
    } else {
      this.state = ENTITY_STATE_ENUM.AIRDEAD
    }

  }




}
